package top.xzxsrq.common.utils;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;

import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

public abstract class TreeDataHelperZX {
    private static <T, S> void listTreeList(List<S> list, List<T> children, String parentFieldId, String fieldId, String childrenField, Class<T> resultClass) {
        if (CollectionUtils.isNotEmpty(children)) {
            for (T child : children) {
                List<T> children1 = getChildren(list, child, fieldId, parentFieldId, resultClass);
                TreeDataHelperZX.listTreeList(list, children1, parentFieldId, fieldId, childrenField, resultClass);
                ObjectUtilsZX.setValue(child, childrenField, children1);
            }
        }
    }

    private static <T, S> List<T> getChildren(List<S> list, Object child, String fieldId, String parentFieldId, Class<T> resultClass) {
        Object value = ObjectUtilsZX.getValue(child, fieldId);
        return list.stream().filter(i -> {
                    Object value1 = ObjectUtilsZX.getValue(i, parentFieldId);
                    return Objects.equals(value, value1);
                }).map(i -> {
                    T item = null;
                    try {
                        item = resultClass.newInstance();
                        BeanUtils.copyProperties(i, item, ObjectUtilsZX.getNullPropertyNames(i));
                        return item;
                    } catch (InstantiationException | IllegalAccessException e) {
                        e.printStackTrace();
                    }
                    return item;
                }).filter(ObjectUtilsZX::isNotEmpty)
                .collect(Collectors.toList());
    }

    /**
     * 列表装成树
     *
     * @param list
     * @param parentFieldId
     * @param fieldId
     * @param childrenField
     * @param resultClass
     * @param isRoot        自己判断根节点, 如果这个是null 则用代码自带的判断方式
     * @param <T>
     * @param <S>
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public static <T, S> List<T> listTreeList(List<S> list, String parentFieldId, String fieldId, String childrenField, Class<T> resultClass, Function<S, Boolean> isRoot) throws IllegalAccessException, InstantiationException {
        if (ObjectUtilsZX.getField(resultClass, childrenField) == null) {
            throw new RuntimeException("实体类型没有:" + childrenField + "字段");
        }
        boolean b = list.stream()
                .anyMatch(i -> ObjectUtilsZX.isEmpty(ObjectUtilsZX.getValue(i, fieldId)));
        if (b) {
            throw new RuntimeException("愿列表中存在:" + fieldId + "字段为空");
        }
        List<S> collect = list.stream().filter(i -> {
            if (isRoot != null) {
                return isRoot.apply(i);
            }
            Object value = ObjectUtilsZX.getValue(i, parentFieldId);
            return ObjectUtilsZX.isEmpty(value);
        }).collect(Collectors.toList());
        List<T> result = new LinkedList<>();
        for (S s : collect) {
            T t = resultClass.newInstance();
            BeanUtils.copyProperties(s, t, ObjectUtilsZX.getNullPropertyNames(s));
            List<T> children = getChildren(list, s, fieldId, parentFieldId, resultClass);
            TreeDataHelperZX.listTreeList(list, children, parentFieldId, fieldId, childrenField, resultClass);
            ObjectUtilsZX.setValue(t, childrenField, children);
            result.add(t);
        }
        return result;
    }

    /**
     * 列表装成树
     *
     * @param list
     * @param parentFieldId
     * @param fieldId
     * @param childrenField
     * @param resultClass
     * @param <T>
     * @param <S>
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public static <T, S> List<T> listTreeList(List<S> list, String parentFieldId, String fieldId, String childrenField, Class<T> resultClass) throws IllegalAccessException, InstantiationException {
        return listTreeList(list, parentFieldId, fieldId, childrenField, resultClass, null);
    }

    /**
     * 列表装成树
     *
     * @param list
     * @param resultClass
     * @param isRoot      自己判断根节点, 如果这个是null 则用代码自带的判断方式
     * @param <T>
     * @param <S>
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static <T, S> List<T> listTreeList(List<S> list, Class<T> resultClass, Function<S, Boolean> isRoot) throws InstantiationException, IllegalAccessException {
        return listTreeList(list, "parentId", "id", "children", resultClass, isRoot);
    }

    /**
     * 列表装成树
     *
     * @param list
     * @param resultClass
     * @param <T>
     * @param <S>
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static <T, S> List<T> listTreeList(List<S> list, Class<T> resultClass) throws InstantiationException, IllegalAccessException {
        return listTreeList(list, "parentId", "id", "children", resultClass);
    }

    /**
     * 列表递归查找上下关系的值
     *
     * @param list
     * @param parentFieldValue
     * @param nextFieldName
     * @param selfFieldName
     * @param <T>
     * @return
     */
    public static <T> List<String> listRecursiveLookupValue(List<T> list, String parentFieldValue, String nextFieldName, String selfFieldName) {
        if (StringUtils.isEmpty(parentFieldValue)) {
            return null;
        }
        List<T> collect = list.stream()
                .filter(i -> parentFieldValue.equals(ObjectUtilsZX.getValue(i, nextFieldName)))
                .collect(Collectors.toList());
        List<String> result = collect.stream()
                .map(i -> Objects.requireNonNull(ObjectUtilsZX.getValue(i, selfFieldName)).toString())
                .filter(StringUtils::isNotEmpty)
                .collect(Collectors.toCollection(LinkedList::new));
        for (T t : collect) {
            List<String> strings = listRecursiveLookupValue(list, Objects.requireNonNull(ObjectUtilsZX.getValue(t, selfFieldName)).toString(), nextFieldName, selfFieldName);
            if (CollectionUtils.isNotEmpty(strings)) {
                result.addAll(strings);
            }
        }
        return result;
    }

    /**
     * 列表递归查找上下关系的值 默认查找 parentId 和 id 的关系
     *
     * @param list
     * @param parentFieldValue
     * @param <T>
     * @return
     */
    public static <T> List<String> listRecursiveLookupValue(List<T> list, String parentFieldValue) {
        return listRecursiveLookupValue(list, parentFieldValue, "parentId", "id");
    }

    /**
     * 遍历树形结构
     *
     * @param list
     * @param field    子集字段
     * @param refDetZX
     * @param callBack 回调函数
     * @param <T>
     */
    public static <T> void eachTreeList(List<T> list, String field, RefDetZX refDetZX, Consumer<T> callBack) {
        for (T t : list) {
            refDetZX.add(t);
            callBack.accept(t);
            Object value = ObjectUtilsZX.getValue(t, field);
            if (refDetZX.contains(value)) {
                return;
            }
            if (value instanceof List && CollectionUtils.isNotEmpty((List<T>) value)) {
                TreeDataHelperZX.eachTreeList((List<T>) value, field, refDetZX, callBack);
            }
        }
    }

    /**
     * 遍历树形结构
     *
     * @param list
     * @param field    子集字段
     * @param callBack 回调函数
     * @param <T>
     */
    public static <T> void eachTreeList(List<T> list, String field, Consumer<T> callBack) {
        eachTreeList(list, field, new RefDetZX(), callBack);
    }

    /**
     * 遍历树形结构
     *
     * @param list
     * @param field    子集字段
     * @param callBack 回调函数
     * @param <T>
     */
    public static <T> void eachTreeList(List<T> list, String field, BiConsumer<T, List<T>> callBack) {
        eachTreeList(list, field, new LinkedList<>(), callBack, new RefDetZX());
    }

    private static <T> void eachTreeList(List<T> list, String field, List<T> path, BiConsumer<T, List<T>> callBack, RefDetZX refDetZX) {
        for (T t : list) {
            refDetZX.add(t);
            callBack.accept(t, path);
            Object value = ObjectUtilsZX.getValue(t, field);
            if (refDetZX.contains(value)) {
                return;
            }
            if (value instanceof List && CollectionUtils.isNotEmpty((List<T>) value)) {
                List<T> parentPath = new LinkedList<>(path);
                parentPath.add(t);
                eachTreeList((List<T>) value, field, parentPath, callBack, refDetZX);
            }
        }
    }

    /**
     * 查找父级
     *
     * @param list
     * @param getGrand      是否查找曾级
     * @param field         识别的字段
     * @param childrenField 子集字段
     * @param <T>
     * @return
     */
    public static <T> List<T> getParent(List<T> list, T source, boolean getGrand, String field, String childrenField) {
        Object value1 = ObjectUtilsZX.getValue(source, field);
        List<T> result = new LinkedList<>();
        if (ObjectUtilsZX.isEmpty(value1)) {
            return result;
        }
        try {
            TreeDataHelperZX.eachTreeList(list, childrenField, (item, path) -> {
                Object value = ObjectUtilsZX.getValue(item, field);
                if (Objects.equals(value1, value)) {
                    if (CollectionUtils.isNotEmpty(path)) {
                        if (getGrand) {
                            result.addAll(path);
                        } else {
                            result.add(path.get(0));
                        }
                    }
                    throw new RuntimeException();
                }
            });
        } catch (Exception ignore) {
        }
        return result;
    }
}
